package com.gitee.wsl.compose.ui.richtext.theme

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.graphics.isUnspecified
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontSynthesis
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.LocaleList
import androidx.compose.ui.text.style.BaselineShift
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextGeometricTransform
import androidx.compose.ui.text.style.TextIndent
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.sp
import com.gitee.wsl.compose.ui.richtext.content.ParagraphContent

/**
 * Styling configuration for a text span.
 *
 * In the process of merging several Spans in one [SpanStyle],
 * instead of creating several SpanStyles and merging them together,
 * we use [MutableSpanStyle] to consider the values as non-deterministic
 * and after the process is finished, convert it into a [SpanStyle].
 */
@Suppress("MemberVisibilityCanBePrivate")
class MutableSpanStyle internal constructor(
    var linkColor: Color = Color.Unspecified,
    var color: Color = Color.Unspecified,
    var fontSize: TextUnit = TextUnit.Unspecified,
    var fontWeight: FontWeight? = null,
    var fontStyle: FontStyle? = null,
    var fontSynthesis: FontSynthesis? = null,
    var fontFamily: FontFamily? = null,
    var fontFeatureSettings: String? = null,
    var letterSpacing: TextUnit = TextUnit.Unspecified,
    var baselineShift: BaselineShift? = null,
    var background: Color = Color.Unspecified,
    var textDecoration: TextDecoration? = null,
    var textGeometricTransform: TextGeometricTransform? = null,
    var localeList: LocaleList? = null,
    var shadow: Shadow? = null,
    var appearance: SpanStyle? = null,
    var linkColorMapper:  Color? = null
) {

    val paragraphContents = mutableListOf<ParagraphContent>()
    //internal var urlSpan: URLSpan? = null

    fun toSpanStyle(): SpanStyle {
        return SpanStyle(
            color = if (color.isUnspecified) {
                val mappedColor = linkColorMapper
                if (mappedColor != null && mappedColor.isSpecified) {
                    mappedColor
                } else {
                    linkColor
                }
            } else {
                color
            },
            fontSize = fontSize,
            fontWeight = fontWeight,
            fontStyle = fontStyle,
            fontSynthesis = fontSynthesis,
            fontFamily = fontFamily,
            fontFeatureSettings = fontFeatureSettings,
            letterSpacing = letterSpacing,
            baselineShift = baselineShift,
            background = background,
            textDecoration = textDecoration,
            localeList = localeList,
            shadow = shadow,
            textGeometricTransform = textGeometricTransform
        ).merge(appearance)
    }

    fun toParagraphStyle(): ParagraphStyle? {
        if (hasParagraphStyle().not()) {
            return null
        }

        var first = 0
        var rest = 0
        var lineHeight: Int? = null
        var alignment: TextAlign? = null
        paragraphContents.forEach { paragraph ->
            first = paragraph.firstLeadingMargin ?: first
            rest = paragraph.restLeadingMargin ?: rest
            lineHeight = paragraph.lineHeight ?: lineHeight
            alignment = paragraph.alignment ?: alignment
        }

        val indent = if (first != 0 || rest != 0) {
            TextIndent(firstLine = first.sp, restLine = rest.sp)
        } else null

        return ParagraphStyle(
            textAlign = alignment ?: TextAlign.Unspecified,
            textIndent = indent,
            lineHeight = lineHeight?.sp ?: TextUnit.Unspecified
        )
    }

    fun hasParagraphStyle() = paragraphContents.isNotEmpty()
}